package com.netty.utils;
import java.util.TimerTask;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicLong;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TimedSupervisorTask extends TimerTask {
    private static final Logger logger = LoggerFactory.getLogger(TimedSupervisorTask.class);
    private final ScheduledExecutorService scheduler;
    private final ThreadPoolExecutor executor;
    private final long timeoutMillis;
    private final Runnable task;
    private final AtomicLong delay;
    private final long maxDelay;

    public TimedSupervisorTask(String name,
                               ScheduledExecutorService scheduler,
                               ThreadPoolExecutor executor,
                               int timeout,
                               TimeUnit timeUnit,
                               int expBackOffBound,
                               Runnable task) {
        this.scheduler = scheduler;
        this.executor = executor;
        this.timeoutMillis = timeUnit.toMillis((long)timeout);
        this.task = task;
        this.delay = new AtomicLong(this.timeoutMillis);
        this.maxDelay = this.timeoutMillis * (long)expBackOffBound;
    }

    public void run() {
        Future future = null;
        try {
            future = this.executor.submit(this.task);
            future.get(this.timeoutMillis, TimeUnit.MILLISECONDS);
            this.delay.set(this.timeoutMillis);
        } catch (TimeoutException var12) {
            logger.warn("task supervisor timed out", var12);
            long currentDelay = this.delay.get();
            long newDelay = Math.min(this.maxDelay, currentDelay * 2L);
            this.delay.compareAndSet(currentDelay, newDelay);
        } catch (RejectedExecutionException var13) {
            if (!this.executor.isShutdown() && !this.scheduler.isShutdown()) {
                logger.warn("task supervisor rejected the task", var13);
            } else {
                logger.warn("task supervisor shutting down, reject the task", var13);
            }
        } catch (Throwable var14) {
            if (!this.executor.isShutdown() && !this.scheduler.isShutdown()) {
                logger.warn("task supervisor threw an exception", var14);
            } else {
                logger.warn("task supervisor shutting down, can't accept the task");
            }
        } finally {
            if (future != null) {
                future.cancel(true);
            }

            if (!this.scheduler.isShutdown()) {
                this.scheduler.schedule(this, this.delay.get(), TimeUnit.MILLISECONDS);
            }

        }

    }
}
